package com.swust.security.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.annotation.Resource;
import javax.sql.DataSource;

/**
 * @Author hqf
 * @Date Created in 2021/9/11 9:32
 * @Description
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private UserDetailsService userDetailsService;

    // 注入数据源
    @Autowired
    private DataSource dataSource;

    @Bean
    public PersistentTokenRepository persistentTokenRepository(){
        JdbcTokenRepositoryImpl jdbcTokenRepository = new
                JdbcTokenRepositoryImpl();
        // 赋值数据源
        jdbcTokenRepository.setDataSource(dataSource);
        // 自动创建表,第一次执行会创建，以后要执行就要删除掉！
//        jdbcTokenRepository.setCreateTableOnStartup(true);
        return jdbcTokenRepository;
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

//    @Override
//    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        String password = passwordEncoder().encode("123");
//        auth.inMemoryAuthentication().withUser("lucy").password(password).roles("admin");
//
//    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    /**
     * 角色和权限
     * 同一个角色可能有不同的权限
     * 比如老师和学生的角色都是系统的用户
     * 但是老师有修改成绩和查成绩的权限，而学生只有查的权限
     * 角色：管理员
     * 权限：增删改查
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 自定义无权限页面
        http.exceptionHandling().accessDeniedPage("/unauth");
        // 自定义自己编写的登录页面
        http.formLogin()
                .loginPage("/") // 配置登录页面的url
                .loginProcessingUrl("/user/login") // 登录访问路径 只有前端表单请求路径和这里一致时,用户登录逻辑才会在UserDetailService处理
                .defaultSuccessUrl("/test/index").permitAll(); // 默认登录成功之后跳转的路径
        // 用户注销
        http.logout().logoutUrl("/logout").logoutSuccessUrl("/logoutSuccess").permitAll();
        // 用户角色和权限配置
        http.authorizeRequests().antMatchers("/","/test/hello","/user/login").permitAll() // 设置哪些路径能够直接访问
                .antMatchers("/admin/add").hasAuthority("add") // 只有拥有add权限才能访问
                .antMatchers("/admin/delete").hasAuthority("delete") // 只有拥有delete权限才能访问
//                .antMatchers("/test/**").hasAnyAuthority("admin,user") // 只要有其中一个权限就能访问
                .antMatchers("/admin/**").hasRole("admin") // ROLE_admin 当前登录用户,只有具有admin角色才可以访问这个路径  没有权限访问时返回403状态码
//                .antMatchers("/test/**").hasAnyRole("user","admin") // 只要有其中一个角色就能访问
                .anyRequest().authenticated();
        // 开启记住我功能
        http.rememberMe()
                .tokenRepository(persistentTokenRepository())
                .tokenValiditySeconds(60) // 记住我功能持续时间
                .userDetailsService(userDetailsService);
        // 关闭csrf防护
        http.csrf().disable(); 

    }
}
